package me.jiatao.paging3.network.retrofit

import android.util.Log
import com.google.gson.JsonParseException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.withContext
import org.json.JSONException
import retrofit2.HttpException
import java.io.IOException
import java.net.SocketTimeoutException
import java.net.UnknownHostException

/**
 * 网络相关常量
 */
sealed class HttpConst {
    companion object {
        //业务逻辑类
        const val CODE_SUCCESS = 0
        const val CODE_TOKEN_INVALID = 400

        //网络访问类
        const val CODE_NET_ERROR = 4000
        const val CODE_TIMEOUT = 4080
        const val CODE_JSON_PARSE_ERROR = 4010
        const val CODE_SERVER_ERROR = 500

        //域名相关
        const val BASE_URL = "https://www.wanandroid.com/"
    }
}

/**
 * 请求异常处理
 * 将网络请求异常封装为HttpResult对象
 */
suspend inline fun <T> apiCall(crossinline call: suspend CoroutineScope.() -> HttpResult<T>): HttpResult<T> {
    return withContext(Dispatchers.IO) {
        val res: HttpResult<T>
        try {
            res = call()
        } catch (e: Throwable) {
            Log.e("ApiCaller", "request error", e)
            // 请求出错，将状态码和消息封装为 ResponseResult
            return@withContext ApiException.build(e).toResponse<T>()
        }

        if (res.code == HttpConst.CODE_TOKEN_INVALID) {
            //凭证失效，协程取消
            //执行退出登录操作等
            cancel()
        }
        return@withContext res
    }
}


/**
 * 网络、数据解析错误处理
 */
class ApiException(
    private val code: Int,
    override val message: String?,
    override val cause: Throwable? = null
) : RuntimeException(message, cause) {
    companion object {
        // 网络状态码

        fun build(e: Throwable): ApiException {
            return if (e is HttpException) {
                ApiException(HttpConst.CODE_NET_ERROR, "网络异常(${e.code()},${e.message()})")

            } else if (e is UnknownHostException) {
                ApiException(HttpConst.CODE_NET_ERROR, "未识别域名,请检查后再试")

            } else if (e is SocketTimeoutException) {
                ApiException(HttpConst.CODE_TIMEOUT, "请求超时,请稍后再试")

            } else if (e is IOException) {
                ApiException(HttpConst.CODE_NET_ERROR, "网络异常(${e.message})")

            } else if (e is JsonParseException || e is JSONException) {
                // Json解析失败
                ApiException(HttpConst.CODE_JSON_PARSE_ERROR, "数据解析错误,请稍后再试")

            } else {
                ApiException(HttpConst.CODE_SERVER_ERROR, "系统错误(${e.message})")
            }
        }
    }

    fun <T> toResponse(): HttpResult<T> {
        return HttpResult(code, message)
    }
}